#pragma once

#include "Common.h"
#include "Bool.h"
#include "PagingManager.h"

namespace DbReader
{

	#include "BinomCoef.h"

	// EGTB Header Tag for recognizing file format
	extern char* szDBHeaderTag;

	// size of EGTB header tag	
	#define EGTB_HEADER_TAG_SIZE		4

	
	#pragma pack(push, 1) // make alignment to 1 byte

	// The main EGTB header
	struct EGTBMainHeader
	{
	public:
		char szHeaderTag[EGTB_HEADER_TAG_SIZE];			// header tag file format mark
		int32 nDraughtsType;							// PDN code of draughts type
		int32 nCompressionType;							// compression used for the raw data
		uint32 nSubDbCount;								// the count of stored subddatabases
		uint64 nPagingDataOffset;						// global offset to the raw data for Paging Manager
	};

	// record of EGTB subdatabases stored in the compressed EGTB file
	struct EGTBSubDatabase
	{
	public:
		int32 wm;
		int32 wk;
		int32 bm;
		int32 bk;
		int32 wmrank;
		int32 bmrank;
		int32 color;
		uint32 nStartBlock;
		uint32 nStartByteInBlock;
	};

	#pragma pack(pop)

	
	// definition of a structure for compressed databases; either WDL or DTM
	typedef struct compresseddatabase
	{
		int ispresent;			// does db exist?
		int firstblockindb;		// where is the first block in it's db?
		int startbyte;			// at this byte								
		int fp;					// which file is it in?
	} cprsubdb;


	 // CDbReader - EGTB Reader Class supporting multi-threaded access
	//////////////////////////////////////////////////////////////////////////////////////////
	
	template<int MaxPieces, int MaxPiece, int MaxRank>
	class CDbReader
	{
	public:
		// constructor / destructor
		CDbReader();
		~CDbReader();

		// PUBLIC API METHODS
		////////////////////////////////

		// public API method for initializing the EGTB database
		int Initialize(int suggestedMB, SEngineData* ed, const wchar_t* lpDbDir);

		// Looks up the position in the EGTB databases
		template<typename BB, int BitsPerRow, int MaxField>
		int Lookup(BB *q, int cl, uint8 *pDTM);

		inline eCheckersType GetDraughtsType()
		{ return m_eDraughtsType; }

		inline int GetMaxPieces()
		{ return m_nMaxDetectedPieces; }

	private:
		// PRIVATE HELPER METHODS
		////////////////////////////////

		// set the DB directory
		void SetDatabaseDirectory(const wchar_t* lpDir);

		// returns the largest DB found
		int DetectLargestDB();

		// parses the set of EGTB files of one type, either WDL or DTM
		bool ParseSetOfEGTBFiles(int nFpCount, FILE** files, 
			cprsubdb (*pSubDb)[MaxPiece+1][MaxPiece+1][MaxPiece+1][MaxPiece+1][MaxRank][MaxRank][2], 
								PagingManager** ppManager, int64** ppGlobalBlockNumbers);

		// parses one single file
		bool ParseEGTBFile(FILE* fp, int fileIndex, 
				cprsubdb (*pSubDb)[MaxPiece+1][MaxPiece+1][MaxPiece+1][MaxPiece+1][MaxRank][MaxRank][2], 
				int64 *pPagingDataOffset);

		// preloads the database to the cache - Moved to the PagingManager
		void PreloadDatabase(SEngineData* ed, int iNumberOfBlocksWDL, int iNumberOfBlocksDTM);

		// creates a database-file name
		// either DTM file or index file od DB file
		void SetReaderDatabaseName(wchar_t *dbname, int numPieces, bool index, bool dtm);
	

		// PRIVATE VARIABLES
		////////////////////////////////
	
		// compressed subdatabase records
		cprsubdb wdlsubdatabase[MaxPiece+1][MaxPiece+1][MaxPiece+1][MaxPiece+1][MaxRank][MaxRank][2]; 

		// compressed DTM subdatabases records
		cprsubdb dtmsubdatabase[MaxPiece+1][MaxPiece+1][MaxPiece+1][MaxPiece+1][MaxRank][MaxRank][2];

		// Paging Managers
		PagingManager* m_pWDLManager;
		PagingManager* m_pDTMManager;

		// the size of cache - the same value for DTM cache and WDL cache
		int32 m_nCompresssionType;
		eCheckersType m_eDraughtsType;
		int m_nMaxDetectedPieces;
		uint64 m_nCacheSizeMB; 

		// compressed database directory
		wchar_t* m_szReaderDatabaseDir;		

		// open file handlers
		FILE* m_dbfp[MaxPieces];		// WDL files
		FILE* m_dtmdbfp[MaxPieces];		// DTM files

		int64* m_pWDLGlobalBlockNumber;		// global block number of WDL dbs
		int64* m_pDTMGlobalBlockNumber;		// global block number of DTM dbs
	};

}

// include the code
#include "CDbReader.hpp"